<!doctype html>
<html lang="zh-cn">
<head>

    <meta charset="utf-8">
    <meta name="generator" content="Hugo 0.57.2" />
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1">

    <title>Mybatis | The Sky of OtsWang</title>
    <meta property="og:title" content="Mybatis - The Sky of OtsWang">
    <meta property="og:type" content="article">
        
    <meta property="article:published_time" content="2019-05-28T16:54:29&#43;08:00">
        
        
    <meta property="article:modified_time" content="2019-05-28T16:54:29&#43;08:00">
        
    <meta name="Keywords" content="golang,go语言,otswang,java,博客,python">
    <meta name="description" content="Mybatis">
        
    <meta name="author" content="OtsWang">
    <meta property="og:url" content="https://otswang.gitee.io/hugo/post/middle_tools/mybatis/">
    <link rel="shortcut icon" href="/favicon.ico" type="image/x-icon">

    <link rel="stylesheet" href="/hugo/css/normalize.css">
    
        <link rel="stylesheet" href="/hugo/css/prism.css">
    
    <link rel="stylesheet" href="/hugo/css/style.css">
    <script type="text/javascript" src="//cdn.bootcss.com/jquery/3.2.1/jquery.min.js"></script>

    


    
    
</head>

<body>
<header id="header" class="clearfix">
    <div class="container">
        <div class="col-group">
            <div class="site-name ">
                
                    <a id="logo" href="https://otswang.gitee.io/hugo/">
                        The Sky of OtsWang
                    </a>
                
                <p class="description">擅长写HelloWorld的小小码农</p>
            </div>
            <div>
                <nav id="nav-menu" class="clearfix">
                    
                    
                    <a  href="https://otswang.gitee.io/hugo/" title="Home">Home</a>
                    
                    <a  href="https://otswang.gitee.io/hugo/tags/" title="Tags">Tags</a>
                    
                    <a  href="https://otswang.gitee.io/hugo/categories/" title="Categories">Categories</a>
                    
                    <a  href="https://otswang.gitee.io/hugo/archives/" title="Archives">Archives</a>
                    
                    <a  href="https://otswang.gitee.io/hugo/about/" title="About">About</a>
                    
                </nav>
            </div>
        </div>
    </div>
</header>


<div id="body">
    <div class="container">
        <div class="col-group">

            <div class="col-8" id="main">
                <div class="res-cons">
                    <article class="post">
                        <header>
                            <h1 class="post-title">Mybatis</h1>
                        </header>
                        <date class="post-meta meta-date">
                            2019年5月28日
                        </date>
                        
                        <div class="post-meta">
                            <span>|</span>
                            
                                <span class="meta-category"><a href="https://otswang.gitee.io/hugo/categories/middletools">MiddleTools</a></span>
                            
                        </div>
                        
                        
                        
                        <div class="post-content">
                            <p>对mybatis学习的总结</p>

<h2 id="基本用法">基本用法</h2>

<p><strong>动态条件：</strong></p>

<pre><code class="language-sql">&lt;where&gt;
    &lt;if test=&quot;state == 0&quot;&gt;
    and count &gt; 0
    &lt;/if&gt;
&lt;/where&gt;

&lt;if test=&quot;ids != null&quot; &gt;
    id in 
    &lt;foreach item=&quot;item&quot; index=&quot;index&quot; collection=&quot;ids&quot; 
             open=&quot;(&quot; separator=&quot;,&quot; close=&quot;)&quot; &gt;
        #{item}
    &lt;/foreach&gt;
&lt;/if&gt;

&lt;choose&gt;
&lt;when test=&quot;title == null&quot;&gt;
and user_name = &quot;ots&quot;
&lt;/when&gt;
&lt;when test=&quot;user_name == null&quot;&gt;
and title = &quot;&quot;
&lt;/when&gt;
&lt;otherwise&gt;
and user_id = 1
&lt;/otherwise&gt;
&lt;/choose&gt;
</code></pre>

<p><strong>$与#</strong></p>

<p>$ 直接拼接， # 为当成一个参数</p>

<h2 id="sqlsession运行与四大对象">SqlSession运行与四大对象</h2>

<p>SQLsession的运行原理如图：</p>

<p><img src="/hugo/src/img/middle/mybatis-all.png" /></p>

<p>sqlsession 通过<strong>Executor</strong>创建statementHandler来运行，而<strong>StatementHandler</strong>要经过如下三步：</p>

<ul>
<li>prepared 预编译SQL</li>
<li>parameterize设置参数</li>
<li>query/update执行SQL</li>
</ul>

<p>其中parameterize是调用<strong>parameterHandler</strong>的方法去设置的，而参数是根据类型处理器typeHandler 去处理的，query/update方法是通过<strong>resultHandler</strong>进行处理结果的封装，如果是update，返回整数，否则通过typeHandler进行结果类型处理，然后用ObjectFactory提供的规则组装对象，返回给调用者。</p>

<p>四大对象的创建：</p>

<pre><code class="language-java">public Executor newExecutor(Transaction transaction, ExecutorType executorType) {
   //确保ExecutorType不为空(defaultExecutorType有可能为空)
   executorType = executorType == null ? defaultExecutorType : executorType;
   executorType = executorType == null ? ExecutorType.SIMPLE : executorType;
   Executor executor;   if (ExecutorType.BATCH == executorType) {
      executor = new BatchExecutor(this, transaction);
   } else if (ExecutorType.REUSE == executorType) {
      executor = new ReuseExecutor(this, transaction);
   } else {
      executor = new SimpleExecutor(this, transaction);
   }   if (cacheEnabled) {
      executor = new CachingExecutor(executor);
   }
   executor = (Executor) interceptorChain.pluginAll(executor);
   return executor;
}

public StatementHandler newStatementHandler(Executor executor, 
                                            MappedStatement mappedStatement, 
                                            Object parameterObject, 
                                            RowBounds rowBounds, 
                                            ResultHandler resultHandler, 
                                            BoundSql boundSql) {
   StatementHandler statementHandler = new RoutingStatementHandler(executor, 
   mappedStatement, parameterObject, rowBounds, resultHandler, boundSql);
   statementHandler = (StatementHandler) interceptorChain.pluginAll(statementHandler);
   return statementHandler;
}

public ParameterHandler newParameterHandler(MappedStatement mappedStatement, 
                                            Object parameterObject, 
                                            BoundSql boundSql) {
   ParameterHandler parameterHandler = mappedStatement.getLang()
            .createParameterHandler(mappedStatement, parameterObject, boundSql);
   parameterHandler = (ParameterHandler) interceptorChain.pluginAll(parameterHandler);
   return parameterHandler;
}

public ResultSetHandler newResultSetHandler(Executor executor, 
                                            MappedStatement mappedStatement, 
                                            RowBounds rowBounds, 
                                            ParameterHandler parameterHandler, 
                                            ResultHandler resultHandler, 
                                            BoundSql boundSql) {
   ResultSetHandler resultSetHandler = new DefaultResultSetHandler(executor, 
   mappedStatement, parameterHandler, resultHandler, boundSql, rowBounds);·
   resultSetHandler = (ResultSetHandler) interceptorChain.pluginAll(resultSetHandler);
   return resultSetHandler;
}
</code></pre>

<h2 id="插件">插件</h2>

<p>Mybatis插件又称拦截器，mybatis使用责任链模式，通过动态代理组织多个插件，通过这些插件可以改变mybatis的默认行为，比如SQL重写。</p>

<p>在Configuration对象的创建方法里使用调用链封装，我们可以在四大对象调度的时候插入代码去执行一些特殊的代码，这便是mybatis的插件技术。</p>

<p>mybatis插件需要实现Interceptor接口，源码如下：</p>

<pre><code class="language-java">package org.apache.ibatis.plugin;

import java.util.Properties;

public interface Interceptor {
    Object intercept(Invocation var1) throws Throwable;

    Object plugin(Object var1);

    void setProperties(Properties var1);
}
</code></pre>

<p>在configuration中，插件的保存：</p>

<pre><code class="language-java">protected final InterceptorChain interceptorChain;

/**
 * ...
 */

public void addInterceptor(Interceptor interceptor) {
    this.interceptorChain.addInterceptor(interceptor);
}
</code></pre>

<p>插件用的是责任链模式：一个对象（四大对象中的一个），在多个角色中传递，处在传递链上的任何一个角色都有处理它的机会。每一个在责任链上的角色都有机会去拦截这个对象，在将来如果有新的角色添加，也可以轻松拦截该请求对象，进行处理。</p>

<p><strong>MetaObject</strong></p>

<p>可以有效的读取或者修改一些重要对象的属性。在mybatis中，四大对象的很多参数方法都不是public的，使用这个类可以很方便的修改读取对象的属性。</p>

<p>一些重要方法</p>

<ul>
<li><code>MetaObject forObject(...)</code>, 已经不再使用，而是使用<code>SystemMetaObject.forObject(Object obj)</code>。</li>
<li><code>Object getValue(String name)</code></li>
<li><code>void setValue(String name, Object value)</code></li>
</ul>

<p><strong>插件开发示例</strong></p>

<ol>
<li>拦截的签名</li>
</ol>

<p><strong>确定拦截的对象</strong></p>

<ul>
<li>Excutor 是执行SQL的全过程，包括组装参数，组装结果集返回和执行SQL，较为广泛： 拦截执行器方法</li>
<li>StatementHandler 是执行SQL的过程：拦截SQL语法构建的处理</li>
<li>ParameterHandler 参数组装，可以重写组装参数规则：拦截参数的处理</li>
<li>ResultSetHandler 执行结果的组装，可以重写组装结果的规则：拦截结果集的处理</li>
</ul>

<p><strong>拦截方法和参数</strong></p>

<p>一般拦截StatementHandler即可，其源码如下，</p>

<pre><code class="language-java">public interface StatementHandler {
    Statement prepare(Connection var1, Integer var2) throws SQLException;

    void parameterize(Statement var1) throws SQLException;

    void batch(Statement var1) throws SQLException;

    int update(Statement var1) throws SQLException;

    &lt;E&gt; List&lt;E&gt; query(Statement var1, ResultHandler var2) throws SQLException;

    &lt;E&gt; Cursor&lt;E&gt; queryCursor(Statement var1) throws SQLException;

    BoundSql getBoundSql();

    ParameterHandler getParameterHandler();
}

</code></pre>

<p><code>prepare</code>方法用来预编译SQL, 我们拦截此方法，因此一般的拦截器结构如下：</p>

<pre><code class="language-java">@Intercepts({
        @Signature(type = StatementHandler.class,
                method = &quot;prepare&quot;,
                args = {Connection.class})
})
public class MyPlugin implements Interceptor {

    Properties props = null;

    /**
     * 代替拦截对象方法的内容
     * @param invocation 责任链对象
     * @return
     * @throws Throwable
     */
    @Override
    public Object intercept(Invocation invocation) throws Throwable {

        Object obj = invocation.proceed();

        return obj;
    }

    /**
     * 生成对象的代理
     * @param o 被代理的对象
     * @return
     */
    @Override
    public Object plugin(Object o) {
        return Plugin.wrap(o, this);
    }

    /**
     * 获取插件配置的属性，在mybatis的配置文件中配置
     * @param properties
     */
    @Override
    public void setProperties(Properties properties) {
        this.props = properties;
    }
}
</code></pre>
                        </div>

                        


                        


                        <div class="post-meta meta-tags">
                            
                            <ul class="clearfix">
                                
                                <li><a href="https://otswang.gitee.io/hugo/tags/mybatis">mybatis</a></li>
                                
                            </ul>
                            
                        </div>
                    </article>
                    
    

    
    
                </div>
            </div>
            <div id="secondary">

    <section class="widget">
        <form id="search" action="//www.google.com/search" method="get" accept-charset="utf-8" target="_blank" _lpchecked="1">
      
      <input type="text" name="q" maxlength="20" placeholder="Search">
      <input type="hidden" name="sitesearch" value="https://otswang.gitee.io/hugo/">
      <button type="submit" class="submit icon-search"></button>
</form>
    </section>

    
    <div class="clear">
        <div class="toc-article">
            <div class="toc-title">文章目录</dixsv>
            <nav id="TableOfContents">
<ul>
<li>
<ul>
<li><a href="#基本用法">基本用法</a></li>
<li><a href="#sqlsession运行与四大对象">SqlSession运行与四大对象</a></li>
<li><a href="#插件">插件</a></li>
</ul></li>
</ul>
</nav>
        </div>
    </div>
    

</div>
        </div>
    </div>
</div>
<footer id="footer">
    <div class="container">
        &copy; 2020 <a href="https://otswang.gitee.io/hugo/">The Sky of OtsWang By OtsWang</a>.
        Powered by <a rel="nofollow noreferer noopener" href="https://gohugo.io" target="_blank">Hugo</a>.
        <a href="https://www.flysnow.org/" target="_blank">Theme</a> based on <a href="https://github.com/Dudiao137/maupassant-hugo" target="_blank">maupassant-ots</a>.
        
    </div>
</footer>


    <script type="text/javascript">
    
    (function(){
        $("pre code").parent().addClass("line-numbers")
    }())

    window.MathJax = {
        tex2jax: {
            inlineMath: [ ['$','$'] ],
            processEscapes: true
        }
    };
    </script>
    <script type="text/javascript" src="/hugo/js/prism.js" async="true"></script>
    <script src='https://cdnjs.cloudflare.com/ajax/libs/mathjax/2.7.5/MathJax.js?config=TeX-MML-AM_CHTML' async></script>

<a id="rocket" href="#top"></a>
<script type="text/javascript" src="/hugo/js/totop.js?v=0.0.0" async=""></script>







 
 <script src="https://mermaidjs.github.io/scripts/mermaid.min.js"></script>
 <script>
       mermaid.initialize({ startOnLoad: true });
 </script>
</body>
</html>
